/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
//								Manager Module
/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/

/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
//							Includes And Defines
/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
#define _CRT_SECURE_NO_WARNINGS

#include <WinSock2.h>
#include <stdlib.h>
#include "Types.h"
#include "ServerClientTools.h"
#include "SocketSendRecvTools.h"
#include "GeneralFunctions.h"
#include "Hw4RandomNumbers.h"
#include "Algorithms.h"
#include "VectorOperations.h"



#define MAX_NUM_OF_NODES 64
#define DEBUG_MODE

/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
//						Internal Structs Declaration
/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
typedef struct 
{
	SOCKET MainSocket;
	TBattery *Batteries;
	int *NumOfBatteries;
} TAcceptConnectionsFromBatteriesThreadArgs;

typedef struct
{
	TBattery *Battery;
	double DistanceFromRocket;
} TBatteryDistance;

/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
//					Internal Functions Declaration
/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/

/*
 * CompareBatteryDistances
 * =========================
 * Function Description: This function is used to sort the batteries from the closest one to the farthest one.
 * Arguments: FirstBattery		A pointer to the first battery to compare
 * 			  SecondBattery		A pointer to the second battery to compare
 * Return Value: 
 * 					A positive integer - if the distance to the first battery is bigger then the distance to the second battery
 * 					A negative integer - if the distance to the second battery is bigger then the distance to the first battery
 *					Zero 			   - if the distance to both batteries is the same.
 */
int CompareBatteryDistances(const void* FirstBattery, const void* SecondBattery);

/*
 * AcceptConnectionsFromBatteriesThread
 * ====================================
 * Function Description: The main function of the thread listening to the main socket and accepts connection from the batteries. 
 * Arguments: AcceptConncectionsArgs	A struct containing the data needed to listen for new connections. 
 * 										See the struct definition for more info.
 */
void AcceptConnectionsFromBatteriesThread(TAcceptConnectionsFromBatteriesThreadArgs *AcceptConncectionsArgs);

/*
 * LaunchInterceptors
 * =========================
 * Function Description: Decides weather to launch interceptors in the current turn. It then asks the relevant batteries
 *                       to launch the interceptors and waits for a reply from the batteries.
 * Arguments: RocketsMap		An array of the current flying rockets
 * 			  NumOfRockets		An int of the number of rockets in the air (number of rockets in the rockets map)
 *			  Batteries[]		An array of the batteries
 *			  NumOfBatteries	the number of batteries in the batteries array
 */
void LaunchInterceptors(TRocket *RocketsMap, int NumOfRockets, TBattery Batteries[], int NumOfBatteries);

/*
 * CompareRocketMapsAndEstimateVelocities
 * =========================
 * Function Description: Compares the current rocket map (received from the simulator) to the rocket map of the 
 *                       previous turn and:
 *                            - Calculate the velocities of flying rockets
 *                            - Determine if rockets have exploded (based on rockets that disappeared from the radar)
 *                            - Determine if any new rockets have been fired
 * Arguments: OldRocketsMap			The rocket map of the previous turn
 * 			  OldNumOfRockets		The number of rockets in the old rockets map
 * 	          CurrentRocketsMap		The rocket map of the current turn
 * 			  NewNumOfRockets		The number of rockets in the new rockets map
 */
void CompareRocketMapsAndEstimateVelocities(TRocket *OldRocketsMap, int OldNumOfRockets, TRocket *CurrentRocketsMap, int NewNumOfRockets);

/*
 * PrintRocketMap
 * =========================
 * Function Description: A debug function that prints a rocket map to the screen
 * Arguments: RocketsMap		A rockets map (an array of rockets)
 * 			  NumOfRockets		The number of rockets in the rockets map
 */
void PrintRocketMap(TRocket *RocketsMap, int NumOfRockets);

/*
 * UpdateBatteriesWithPositionsMap
 * ===============================
 * Function Description: Updates each battery with the current positions of the rockets its interceptors are chasing.
 * Arguments: Rockets 	An array of rockets (the rockets map)
 * 			  NumOfRockets		The number of rockets in the rockets map
 *            Batteries 		The batteries array
 *            NumOfBatteries 	The number of batteries in the batteries array
 */
void UpdateBatteriesWithPositionsMap(TRocket *Rockets, int NumOfRockets, TBattery *Batteries, int NumOfBatteries);

/*
 * UpdateBatteriesOnExplodedRockets
 * =========================
 * Function Description: Updates the relevant battery if a rocket exploded so that the battery could ask the 
 *                       relevant interceptor to self destruct.
 * Arguments: Rockets 	An array of rockets (the rockets map)
 * 			  NumOfRockets		The number of rockets in the rockets map
 *            Batteries 		The batteries array
 *            NumOfBatteries 	The number of batteries in the batteries array
 */
void UpdateBatteriesOnExplodedRockets(TRocket *Rockets, int NumOfRockets, TBattery *Batteries, int NumOfBatteries);

/*
 * FindClosestBattery
 * =========================
 * Function Description: Finds the closest battery to a specific rocket.
 * Arguments: Rocket			A specific rocket that we want to find the closest battery to.
 *            Batteries 		The batteries array
 *            NumOfBatteries 	The number of batteries in the batteries array
 * Return Value: A pointer to the closest battery to the specific rocket.
 */
TBattery* FindClosestBattery(TRocket *Rocket, TBattery *Batteries, int NumOfBatteries);

/*
 * NotifyInterceptorsToChangeBatteries
 * =========================
 * Function Description: Looks at the current rockets and batteries maps and decides if any interceptor should switch batteries.
 *                       If so, it uses the function NotifyBatteryToNotifyInterceptorToChangeBattery to issue a change battery
 *                       request.
 * Arguments: Rockets 	An array of rockets (the rockets map)
 * 			  NumOfRockets		The number of rockets in the rockets map
 *            Batteries 		The batteries array
 *            NumOfBatteries 	The number of batteries in the batteries array
 */
void NotifyInterceptorsToChangeBatteries(TRocket *Rockets, int NumOfRockets, TBattery *Batteries, int NumOfBatteries);

/*
  * NotifyBatteryToNotifyInterceptorToChangeBattery
  * =========================
  * Function Description: Asks the battery that one of its interceptors is chasing a specific rocket to ask the
  *                       interceptor to a different battery. This function is blocking, meanning it will not return 
  *                       until the new battery has aproved that the interceptor has registered with it.
  * Arguments:  RocketID		The chased rocket's ID
  * 			OldBattery		A pointer to the battery the interceptor is currently controled by
  *				NewBattery 		A pointer to the battery the interceptor should switch to.	
  */ 
BOOL NotifyBatteryToNotifyInterceptorToChangeBattery(int RocketID, TBattery *OldBattery, TBattery *NewBattery);

/*
 * WriteBatteriesAndRadarsOutputFile
 * =========================
 * Function Description: Writes the batteries and radar output file.
 * Arguments: OutputFileName		A string of the name for the output file
 *            Batteries 			The batteries array
 *            NumOfBatteries 		The number of batteries in the batteries array
 *			  RadarPosition			The radar's position
 * Return Value: TRUE on success, FALSE on failure.
 */
BOOL WriteBatteriesAndRadarsOutputFile(const char *OutputFileName, TBattery *Batteries, int NumOfBatteries, TPosition RadarPosition);

/*
 * NotifyBatteriesEndOfRound
 * =========================
 * Function Description: Notifies all batteries that the round has ended. 
 * Arguments: Batteries 			The batteries array
 *            NumOfBatteries 		The number of batteries in the batteries array
 */
void NotifyBatteriesEndOfRound(TBattery *Batteries, int NumOfBatteries);

/*
 * NotifyBatteriesEndOfGame
 * =========================
 * Function Description: Notifies all batteries that the game has ended and they should exit.
 * Arguments: Batteries 			The batteries array
 *            NumOfBatteries 		The number of batteries in the batteries array
 */
void NotifyBatteriesEndOfGame(TBattery *Batteries, int NumOfBatteries);

/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
//					END OF Internal Functions Declaration
/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/


/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
//					Manager Module - Main function
/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/


void MainManager(int argc, char *argv[])
{
	SOCKET ClockSocket, SimulatorSocket;
	char *SelfIP = argv[2];
	int SelfPort = atoi(argv[3]);
	char *ClockIP = argv[4];
	int  ClockPort = atoi(argv[5]);
	char *SimulatorIP = argv[6];
	int SimulatorPort = atoi(argv[7]);
	double RadarAccuracy = atof(argv[8]);
	unsigned int Seed;
	TPosition RadarPosition;

	SOCKET MainSocket;
	HANDLE AcceptConnectcionsThreadHandle;
	TBattery StaticBatteries[MAX_NUM_OF_NODES]; //start with a maximum size array, after all nodes finished registering, copy into smaller array
	TBattery *Batteries = NULL;
	TRocket *OldRocketsMap = NULL;
	TRocket *CurrentRocketsMap = NULL;
	int CurrentNumOfRockets = 0;
	int OldNumOfRockets = 0;
	int NumOfBatteries = 0;
	int RoundNum;
	TAcceptConnectionsFromBatteriesThreadArgs AcceptConncectionsArgs;

	RadarPosition.x = atof(argv[9]);
	RadarPosition.y = atof(argv[10]);
	
	//accept optional argument
	if (argc == 12)
	{
		Seed = atoi(argv[11]);
		#ifdef DEBUG_MODE
			printf("DEBUG: Optional seed has been given. Initializing random with seed: %d\n", Seed);
		#endif
		InitializeRandomNumberGenerator(Seed);
	}
	else
	{
		InitializeRandomNumberGeneratorWithoutSeed();
	} 

	//Start up sequence
	MainSocket = StartServer(SelfIP, SelfPort);
	printf("Created a server, starting a thread to accept connections from batteries\n");



	AcceptConncectionsArgs.MainSocket = MainSocket;
	AcceptConncectionsArgs.Batteries = StaticBatteries;
	AcceptConncectionsArgs.NumOfBatteries = &NumOfBatteries;
	
	AcceptConnectcionsThreadHandle = CreateThreadSimple((LPTHREAD_START_ROUTINE)AcceptConnectionsFromBatteriesThread, &AcceptConncectionsArgs, NULL);

	// connect to simulator
	// Commented until simulator module is up and running - matan
	
	SimulatorSocket = StartClientAndConnectToServer(SimulatorIP, SimulatorPort);
	IdentifyToServer(MODE_MANAGER, SimulatorSocket);	
	printf("Connected to simulator\n");

	
	// connect to clock
	ClockSocket = StartClientAndConnectToServer(ClockIP, ClockPort);
	printf("DEBUG: Connected to clock\n");
	FinishedStartUpSequence();
	//End of start up sequence, clock should now notify when first round begins.

	RoundNum = WaitForClockToNotifyBeginningOfRound(ClockSocket);
	if (RoundNum == -1)
	{
		PrintErrorAndExit(ERROR_RECEIVING_MESSAGE);
	} // wait for first round to begin
	// move the batteries array from the static array to a dynamic array with the appropriate size
	Batteries = (TBattery*)malloc(sizeof(TBattery)*NumOfBatteries); 
	memcpy(Batteries, StaticBatteries, NumOfBatteries*sizeof(TBattery));


	WriteBatteriesAndRadarsOutputFile("IronDomeLocations.txt", Batteries, NumOfBatteries, RadarPosition);
	while (1)
	{

		// variables
		TActionType ActionType;

		// ENDOF variables
		ActionType = ACTION_BEGINNING_OF_ROUND;
		//getchar();
		while (ActionType != ACTION_END_OF_ROUND)
		{
			ReceiveActionType(&ActionType, SimulatorSocket);
			switch (ActionType)
			{
				case ACTION_UPDATE_POSITIONS_MAP:
				{
					int i;
					// move the current map to another place (the "old" map) and receive the new map from the simulator
					OldRocketsMap = (TRocket*)malloc(sizeof(TRocket)*CurrentNumOfRockets);
					memcpy(OldRocketsMap, CurrentRocketsMap, CurrentNumOfRockets*sizeof(TRocket));// this will not work
					OldNumOfRockets = CurrentNumOfRockets;
					free(CurrentRocketsMap);
					ReceiveInteger(&CurrentNumOfRockets, SimulatorSocket);
					printf("Number of rockets in the air: %d\n", CurrentNumOfRockets);
					CurrentRocketsMap = (TRocket*)malloc(sizeof(TRocket)*CurrentNumOfRockets);
					for (i=0 ; i<CurrentNumOfRockets ; i++)
					{
						ReceiveInteger(&(CurrentRocketsMap[i].RocketID), SimulatorSocket);
						ReceiveVector(&(CurrentRocketsMap[i].Position), SimulatorSocket);
						CurrentRocketsMap[i].ChasingBattery = NULL;
						CurrentRocketsMap[i].Status = M_STATUS_ACTIVE;
						printf("Received information on %d rocket%s\n", i+1, (i>0) ? "s" : ""); 
					}
					printf("Finished receiving rockets map from simulator\n");

					printf("ROCKETS MAP\n");
					for (i = 0; i < CurrentNumOfRockets; i++)
					{
						printf("ID: %d, Position: (%.3g, %.3g)\n", CurrentRocketsMap[i].RocketID, CurrentRocketsMap[i].Position.x, CurrentRocketsMap[i].Position.y);
					}
					AddErrorsToRocketsMap(CurrentRocketsMap, CurrentNumOfRockets, RadarPosition, RadarAccuracy);
					printf("ROCKETS MAP\n");
					for (i = 0; i < CurrentNumOfRockets; i++)
					{
						printf("ID: %d, Position: (%.3g, %.3g)\n", CurrentRocketsMap[i].RocketID, CurrentRocketsMap[i].Position.x, CurrentRocketsMap[i].Position.y);
					}
					printf("Finished adding errors to rockets positions, now comparing rockets maps and estimating velocities\n");
					CompareRocketMapsAndEstimateVelocities(OldRocketsMap, OldNumOfRockets, CurrentRocketsMap, CurrentNumOfRockets);
					printf("Finished updating positions map. Now deciding if to launch interceptors.\n");
					LaunchInterceptors(CurrentRocketsMap, CurrentNumOfRockets, Batteries, NumOfBatteries);
					printf("Finished handling interceptors launch. Now notifying batteries to tell interceptors to change battery (if needed).\n");
					NotifyInterceptorsToChangeBatteries(CurrentRocketsMap, CurrentNumOfRockets, Batteries, NumOfBatteries);
					/*
					each interceptor is related to a rocket. 
					create distances array (between rockets and batteries), sort. if the first battery is different then the one 
					it is related to - notify to change.
					*/
					printf("Updating batteries with positions maps and exploded rockets\n");
					UpdateBatteriesWithPositionsMap(CurrentRocketsMap, CurrentNumOfRockets, Batteries, NumOfBatteries);
					UpdateBatteriesOnExplodedRockets(OldRocketsMap, OldNumOfRockets, Batteries, NumOfBatteries);
					printf("Finished updating batteries with positions maps and exploded rockets\n");
					
					break;
				}
				case ACTION_END_OF_ROUND:
					NotifyBatteriesEndOfRound(Batteries, NumOfBatteries);
					NotifyClockEndOfRound(ClockSocket);
					RoundNum = WaitForClockToNotifyBeginningOfRound(ClockSocket);
					if (RoundNum == -1)
					{
						PrintErrorAndExit(ERROR_RECEIVING_MESSAGE);
					}
					break;
				case ACTION_END_OF_GAME:
					NotifyBatteriesEndOfGame(Batteries, NumOfBatteries);
					closesocket(ClockSocket);
					PrintEndOfGame();
					exit(1);
					break;
			}
		}
	}
}



/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
//					Internal Functions Implementation
/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
int CompareBatteryDistances(const void* FirstBattery, const void* SecondBattery)
{
	const double arg1 = ((TBatteryDistance*)FirstBattery)->DistanceFromRocket;
    const double arg2 = ((TBatteryDistance*)SecondBattery)->DistanceFromRocket;
    if (arg1 - arg2 > 0)
		return 1;
	else if (arg1 - arg2 < 0)
		return -1;
	else
		return 0;
}


void AcceptConnectionsFromBatteriesThread(TAcceptConnectionsFromBatteriesThreadArgs *AcceptConncectionsArgs)
{
	TBattery *Batteries = AcceptConncectionsArgs->Batteries;
	SOCKET MainSocket = AcceptConncectionsArgs->MainSocket;
	int *NumOfBatteries = AcceptConncectionsArgs->NumOfBatteries;
	int i;
	TBattery *CurrentBattery = NULL;
	for (i=0 ; i<MAX_NUM_OF_NODES ; i++)
	{
		SOCKET AcceptedSocket;
		#ifdef DEBUG_MODE
			printf("DEBUG: %d Batteries are connected\n", i);
		#endif
		CurrentBattery = Batteries+i;
		AcceptedSocket = AcceptConnection(MainSocket);
		CurrentBattery->Socket = AcceptedSocket;
		CurrentBattery->BatteryIP = NULL;
		ReceiveVector(&(CurrentBattery->Position), CurrentBattery->Socket);
		#ifdef DEBUG_MODE
		printf("DEBUG: Received Battery position: (%g, %g)\n", CurrentBattery->Position.x, CurrentBattery->Position.y);
		#endif
		ReceiveString(&(CurrentBattery->BatteryIP), CurrentBattery->Socket);
		#ifdef DEBUG_MODE
		printf("DEBUG: Received Battery IP: %s\n", CurrentBattery->BatteryIP);
		#endif
		ReceiveInteger(&(CurrentBattery->BatteryPort), CurrentBattery->Socket);
		#ifdef DEBUG_MODE
		printf("DEBUG: Received Battery port: %d\n", CurrentBattery->BatteryPort);
		#endif
		(*NumOfBatteries)++;
	}
}

void LaunchInterceptors(TRocket *RocketsMap, int NumOfRockets, TBattery Batteries[], int NumOfBatteries)
{
	int RocketInd, BatteryInd;
	TBatteryDistance* BatteriesDistances = (TBatteryDistance*)malloc(sizeof(TBatteryDistance)*NumOfBatteries);
	// for each rocket create an array of battery distances, sort it with qsort and then start asking for launches.
	/*for each rocket:
	1. find closest battery
	2. ask launch from closest battery
	3. receive launch result, if refused go to next closest battery.
	*/

	for (RocketInd=0 ; RocketInd<NumOfRockets ; RocketInd++)
	{
		TRocket *Rocket = RocketsMap+RocketInd;
		BOOL LaunchReqRes = FALSE;
		if (Rocket->Sightings == 2)
		{
			// create sorted distances array
			for (BatteryInd = 0 ; BatteryInd < NumOfBatteries ; BatteryInd++)
			{
				BatteriesDistances[BatteryInd].Battery = Batteries+BatteryInd;
				BatteriesDistances[BatteryInd].DistanceFromRocket = CalculateDistance(Batteries[BatteryInd].Position, Rocket->Position);
			}
			qsort(BatteriesDistances, NumOfBatteries, sizeof(TBatteryDistance), CompareBatteryDistances);

			//ask for launches until successful. 
			for (BatteryInd = 0; BatteryInd < NumOfBatteries; BatteryInd++)
			{
				TBattery *Battery = BatteriesDistances[BatteryInd].Battery;
				SendActionType(ACTION_LAUNCH_INTERCEPTOR, Battery->Socket);
				SendVector(Rocket->Position, Battery->Socket);
				SendVector(Rocket->Velocity, Battery->Socket);
				SendInteger(Rocket->RocketID, Battery->Socket);
				ReceiveBOOL(&LaunchReqRes, Battery->Socket);
				if (LaunchReqRes == TRUE) //Launch was seuccessful
				{
					Rocket->ChasingBattery = Battery;
					Rocket->Status = M_STATUS_ACTIVE;
					printf("Interceptor launched successfuly for rocket %d\n", Rocket->RocketID);
					break;
				}
				else if (LaunchReqRes == FALSE)
				{
					printf("Launch refused\n");
				}
				else
				{
					printf("Receive error\n");

				}
			}
		}
	}
}



int RocketFoundInMap(TRocket *RocketsMap, int NumOfRockets, int RocketID) 
{
	int i;
	for (i=0 ; i<NumOfRockets ; i++)
	{
		if (RocketsMap[i].RocketID == RocketID)
			return i;
	}
	return -1;
}


void CompareRocketMapsAndEstimateVelocities(TRocket *OldRocketsMap, int OldNumOfRockets, TRocket *CurrentRocketsMap, int NewNumOfRockets)
{
	int RocketIndInOldMap, RocketIndInNewMap, RocketIndexInOldMap, RocketID;
	/*
	1. go over all rockets in the new map. if the rocket was present in the old map, update the rocket type in the new map
	2. if it was not present, set rocket type to dandash.
	3. OPTIONAL (not sure if we need to keep the rockets which have disappeared): go over all 
		old rockets. if a rocket does not appear in the new map, the rocket has exploded and should be marked as so.
	*/
	for (RocketIndInNewMap=0 ; RocketIndInNewMap<NewNumOfRockets ; RocketIndInNewMap++)
	{
		RocketID = CurrentRocketsMap[RocketIndInNewMap].RocketID;
		RocketIndexInOldMap = RocketFoundInMap(OldRocketsMap, OldNumOfRockets, RocketID);
		if (RocketIndexInOldMap != -1) //the rocket exists in the old map
		{
			CurrentRocketsMap[RocketIndInNewMap].Sightings = OldRocketsMap[RocketIndexInOldMap].Sightings+1;
			if (CurrentRocketsMap[RocketIndInNewMap].Sightings == 2)
				CurrentRocketsMap[RocketIndInNewMap].RocketType = ROCKET_TYPE_NEW;
			else
				CurrentRocketsMap[RocketIndInNewMap].RocketType = ROCKET_TYPE_KNOWN;
			// calculate velocities
			CurrentRocketsMap[RocketIndInNewMap].Velocity = SubtractVectors(CurrentRocketsMap[RocketIndInNewMap].Position, OldRocketsMap[RocketIndexInOldMap].Position);
			CurrentRocketsMap[RocketIndInNewMap].ChasingBattery = OldRocketsMap[RocketIndexInOldMap].ChasingBattery;
		}
		else // This is a new rocket
		{
			CurrentRocketsMap[RocketIndInNewMap].Sightings = 1;
			CurrentRocketsMap[RocketIndInNewMap].RocketType = ROCKET_TYPE_DANDASH;
		}
	}

	PrintRocketMap(CurrentRocketsMap, NewNumOfRockets);

	//go over old map - if a rocket in the old map is not present in the new map, it has exploded
	for (RocketIndInOldMap = 0; RocketIndInOldMap < OldNumOfRockets; RocketIndInOldMap++)
	{
		RocketID = OldRocketsMap[RocketIndInOldMap].RocketID;
		RocketIndInNewMap = RocketFoundInMap(CurrentRocketsMap, NewNumOfRockets, RocketID);
		if (RocketIndInNewMap == -1)
		{
			OldRocketsMap[RocketIndInOldMap].Status = M_STATUS_EXPLODED;
			printf("\noOoOoOoOoOoOoOoOoOoOoOoOoOoO\n");
			printf(  "           BOOOOOM\n");
			printf(  "    Rocket %d exploded!\n", RocketID);
			printf(  "oOoOoOoOoOoOoOoOoOoOoOoOoOoO\n\n");
		}
	}
}


void PrintRocketMap(TRocket *RocketsMap, int NumOfRockets)
{
	int i;
	TRocket *R;
	printf("Current Rocket Map\n");
	for (i = 0; i < NumOfRockets ; i++)
	{
		R = RocketsMap+i;
		printf("ID: %d, Position: (%.3g, %.3g), Velocity: (%.3g, %.3g), Sightings: %d, ChasingBattery: %s\n", 
		R->RocketID, R->Position.x, R->Position.y, R->Velocity.x, R->Velocity.y, R->Sightings, 
		(R->ChasingBattery == NULL) ? "Not chased" : R->ChasingBattery->BatteryIP	);
	}
	printf("\n");
}



void UpdateBatteriesWithPositionsMap(TRocket *Rockets, int NumOfRockets, TBattery *Batteries, int NumOfBatteries)
{
	int RocketInd;
	TBattery *ChasingBattery = NULL;
	TRocket *Rocket = NULL;
	for (RocketInd = 0; RocketInd < NumOfRockets; RocketInd++)
	{
		Rocket = Rockets+RocketInd;
		ChasingBattery = Rockets[RocketInd].ChasingBattery;

		if (ChasingBattery != NULL)
		{
			SendActionType(ACTION_UPDATE_POSITIONS_MAP, ChasingBattery->Socket);
			SendInteger(Rocket->RocketID, ChasingBattery->Socket);
			SendVector(Rocket->Position, ChasingBattery->Socket);
			SendVector(Rocket->Velocity, ChasingBattery->Socket);
		}
		else
		{
			printf("no chasing battery!\n");
		}
	}
}

void UpdateBatteriesOnExplodedRockets(TRocket *Rockets, int NumOfRockets, TBattery *Batteries, int NumOfBatteries)
{
	int RocketInd;
	TBattery *ChasingBattery = NULL;
	TRocket *Rocket = NULL;

	for (RocketInd = 0; RocketInd < NumOfRockets; RocketInd++)
	{
		Rocket = Rockets+RocketInd;
		ChasingBattery = Rockets[RocketInd].ChasingBattery;
		// printf("Rocket %d %s\n", Rocket->RocketID, (Rocket->Status == M_STATUS_EXPLODED) ? "exploded" : "did not explode");

		if (Rocket->Status == M_STATUS_EXPLODED)
		{
			if (ChasingBattery != NULL)
			{
				SendActionType(ACTION_ROCKET_EXPLODED, ChasingBattery->Socket);
				SendInteger(Rocket->RocketID, ChasingBattery->Socket);
				printf("Notified battery that rocket %d exploded\n", Rocket->RocketID);
			}
		}
	}
}

TBattery* FindClosestBattery(TRocket *Rocket, TBattery *Batteries, int NumOfBatteries)
{
	int i;
	TBattery *ClosestBattery = NULL;
	double Distance = 0;
	double MinDistance = 0;

	for (i = 0; i < NumOfBatteries; i++)
	{
		TBattery *Battery = Batteries+i;
		Distance = CalculateDistance(Battery->Position, Rocket->Position);
		if ((Distance < MinDistance) || (ClosestBattery == 0))
		{
			MinDistance = Distance;
			ClosestBattery = Battery;
		}
	}
	return ClosestBattery;
}

BOOL NotifyBatteryToNotifyInterceptorToChangeBattery(int RocketID, TBattery *OldBattery, TBattery *NewBattery)
{
	TActionType RecAction;
	printf("Asking battery %s to ask interceptor chasing #%d to switch to battery %s\n", OldBattery->BatteryIP, RocketID, NewBattery->BatteryIP);
	SendActionType(ACTION_NOTIFY_INTERCEPTOR_TO_CHANGE_BATTERY, OldBattery->Socket);
	SendInteger(RocketID, OldBattery->Socket);
	SendString(NewBattery->BatteryIP, OldBattery->Socket);
	SendInteger(NewBattery->BatteryPort, OldBattery->Socket);
	ReceiveActionType(&RecAction, OldBattery->Socket);
	if (RecAction == ACTION_CHANGE_BATTERIES)
	{
		ReceiveActionType(&RecAction, NewBattery->Socket);
		if (RecAction == ACTION_NOTIFY_INTERCEPTOR_TO_CHANGE_BATTERY)
			printf("Battery change was succesful\n");
		else
			printf("Battery change failed\n");
		return TRUE;
	}
	else if (RecAction == ACTION_INTERCEPTED) // the interceptor has exploded already
	{
		return FALSE;
	}
}

void NotifyInterceptorsToChangeBatteries(TRocket *Rockets, int NumOfRockets, TBattery *Batteries, int NumOfBatteries)
{
	int RocketInd;
	for (RocketInd = 0; RocketInd < NumOfRockets; RocketInd++)
	{
		TRocket *Rocket = Rockets+RocketInd;
		TBattery *ClosestBattery = FindClosestBattery(Rocket, Batteries, NumOfBatteries);
		if ((Rockets[RocketInd].ChasingBattery != NULL) && (ClosestBattery != Rockets[RocketInd].ChasingBattery))
		{
			if (NotifyBatteryToNotifyInterceptorToChangeBattery(Rocket->RocketID, Rocket->ChasingBattery, ClosestBattery))
			{
				Rocket->ChasingBattery = ClosestBattery;
			}
			else
			{
				Rocket->ChasingBattery = NULL;
			}
		}
	}

}

BOOL WriteBatteriesAndRadarsOutputFile(const char *OutputFileName, TBattery *Batteries, int NumOfBatteries, TPosition RadarPosition)
{
	int i, WriteRes;
	FILE *OutputFile = fopen(OutputFileName, "w");
	if (OutputFile == NULL)
	{
		return FALSE;
	}
	WriteRes = fprintf(OutputFile, "Radar : ( %.3g , %.3g )\n", RadarPosition.x, RadarPosition.y);
	if (WriteRes < 0)
	{
		fclose(OutputFile);
		return FALSE;
	}
	for (i = 0; i < NumOfBatteries; i++)
	{
		TBattery *Battery = Batteries+i;
		WriteRes = fprintf(OutputFile, "Battery : ( %.3g , %.3g )\n", Battery->Position.x, Battery->Position.y);
		if (WriteRes < 0)
		{
			fclose(OutputFile);
			return FALSE;
		}
	}
	fclose(OutputFile);
	return TRUE;
}

void NotifyBatteriesEndOfRound(TBattery *Batteries, int NumOfBatteries)
{
	int i;
	for (i = 0; i < NumOfBatteries; i++)
	{
		SendActionType(ACTION_END_OF_ROUND, Batteries[i].Socket);
	}
}

void NotifyBatteriesEndOfGame(TBattery *Batteries, int NumOfBatteries)
{
	int i;
	for (i = 0; i < NumOfBatteries; i++)
	{
		SendActionType(ACTION_END_OF_GAME, Batteries[i].Socket);
	}
}

/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
//				END OF Internal Functions Implementation
/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/
